package my.org.swing.animate;

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.util.LinkedHashMap;
import javax.swing.JPanel;

/**
 * 按加入顺序依次放置四周，最后1个组件占有中间剩余部分
 */
public class SideLayout implements LayoutManager {

    public static final String NORTH = "North";
    public static final String SOUTH = "South";
    public static final String WEST = "West";
    public static final String EAST = "East";

    public static final String TOP = NORTH;
    public static final String BOTTOM = SOUTH;
    public static final String LEFT = WEST;
    public static final String RIGHT = EAST;

    private LinkedHashMap<Component, String> positionMap = new LinkedHashMap<>();

    private int hgap;

    private int vgap;

    public SideLayout() {
        this(0, 0);
    }

    public SideLayout(int hgap, int vgap) {
        this.hgap = hgap;
        this.vgap = vgap;
    }

    public static JPanel blankPane(int size) {
        JPanel panel = new JPanel();
        panel.setPreferredSize(new Dimension(size, size));
        panel.setOpaque(false);
        return panel;
    }

    @Override
    public void addLayoutComponent(String position, Component comp) {
        if (comp == null) {
            throw new IllegalArgumentException("comp arg is null");
        }

        positionMap.put(comp, checkPosition(position));
    }

    private String checkPosition(String pos) {
        if (NORTH.equalsIgnoreCase(pos)) {
            return NORTH;
        }

        if (SOUTH.equalsIgnoreCase(pos)) {
            return SOUTH;
        }

        if (EAST.equalsIgnoreCase(pos)) {
            return EAST;
        }

        if (WEST.equalsIgnoreCase(pos)) {
            return WEST;
        }

        throw new IllegalArgumentException("Position arg is invalid, must be in North, South, East, West");
    }

    @Override
    public void removeLayoutComponent(Component comp) {
        positionMap.remove(comp);
    }

    @Override
    public Dimension preferredLayoutSize(Container target) {
        synchronized (target.getTreeLock()) {
            Dimension dim = new Dimension(0, 0);
            Component[] components = target.getComponents();
            for (Component c : components) {
                if (!c.isVisible()) {
                    continue;
                }

                String pos = positionMap.get(c);
                Dimension d = c.getPreferredSize();
                if (pos == NORTH || pos == SOUTH) {
                    dim.width = Math.max(d.width, dim.width);
                    dim.height += d.height + vgap;
                } else if (pos == WEST || pos == EAST) {
                    dim.width += d.width + hgap;
                    dim.height = Math.max(d.height, dim.height);
                }
            }

            Insets insets = target.getInsets();
            dim.width += insets.left + insets.right;
            dim.height += insets.top + insets.bottom;

            return dim;
        }
    }

    @Override
    public Dimension minimumLayoutSize(Container target) {
        synchronized (target.getTreeLock()) {
            Dimension dim = new Dimension(0, 0);
            Component[] components = target.getComponents();
            for (Component c : components) {
                if (!c.isVisible()) {
                    continue;
                }

                String pos = positionMap.get(c);
                Dimension d = c.getMinimumSize();
                if (pos == NORTH || pos == SOUTH) {
                    dim.width = Math.max(d.width, dim.width);
                    dim.height += d.height + vgap;
                } else if (pos == WEST || pos == EAST) {
                    dim.width += d.width + hgap;
                    dim.height = Math.max(d.height, dim.height);
                }
            }

            Insets insets = target.getInsets();
            dim.width += insets.left + insets.right;
            dim.height += insets.top + insets.bottom;

            return dim;
        }
    }

    @Override
    public void layoutContainer(Container target) {
        if (positionMap.isEmpty()) {
            return;
        }

        synchronized (target.getTreeLock()) {
            Insets insets = target.getInsets();
            int left = insets.left;
            int right = target.getWidth() - insets.right;
            int top = insets.top;
            int bottom = target.getHeight() - insets.bottom;

            Component[] components = target.getComponents();
            Component last = components[components.length - 1];
            for (Component c : components) {
                if (!c.isVisible()) {
                    continue;
                }

                if (c == last) {
                    c.setBounds(left, top, right - left, bottom - top);
                    return;
                }

                String pos = positionMap.get(c);
                Dimension d = c.getPreferredSize();
                if (pos == NORTH) {
                    c.setBounds(left, top, right, d.height);
                    top += d.height + vgap;
                } else if (pos == SOUTH) {
                    c.setBounds(left, bottom - d.height, right - left, d.height);
                    bottom -= d.height + vgap;
                } else if (pos == WEST) {
                    c.setBounds(left, top, d.width, bottom - top);
                    left += d.width + hgap;
                } else if (pos == EAST) {
                    c.setBounds(right - d.width, top, d.width, bottom - top);
                    right -= d.width + hgap;
                }
            }
        }
    }
}
